/*
 * Problems to solve:
 * How do you use the BufferedReader to create a token?
 * How do you use a switch statement with enum?
 */
package CMinusScanner;

import java.io.File;
import java.io.FileNotFoundException;
import java.util.Scanner;

/**
 * @author Adam Plisch and Austin Klob
 * File: CMinusScanner.java
 * Created: February 2012
 * Copyright Cedarville University, its Computer Science
 * faculty, and the authors. All rights reserved.
 *
 * Description: This class provides the main method
 * and additional supporting methods for the scanning
 * and addition of tokens to the final project.
*/

public class CMinusScanner implements MyScanner {

    private Scanner inFile;
    private Token nextToken;
    private int lineNum = 1;
    private TokenContainer TC = new TokenContainer();
    private String currentLine;
    private int lineWalker = 0;
    private String[] keywords = new String[6];

    public static void main(String[] args) {

        File newFile = new File("src/CMinusScanner/input.txt");
        
        try {
            Scanner myFile = new Scanner(newFile);
            CMinusScanner myScan = new CMinusScanner(myFile);
            myScan.scanToken();
            
            //while(myFile.hasNextLine() == true) {
                myScan.scanToken();
            //}
            
            myScan.TC.printTokens();
            
            myFile.close();
        }
        
        catch (FileNotFoundException ex) {
            System.out.println("Hey you! We have a problem! No file has been found!");
        }
        
        
    }


    //Constructor
    public CMinusScanner(Scanner newFile) {
        nextToken = null;
        inFile = newFile;
        currentLine = inFile.nextLine();
        keywords[0] = "else";
        keywords[1] = "if";
        keywords[2] = "int";
        keywords[3] = "return";
        keywords[4] = "void";
        keywords[5] = "while";
    }

    @Override
    public Token viewNextToken() {
        return nextToken;
    }

    @Override
    public Token getNextToken() {
        Token returnToken = nextToken;
        if (nextToken.getType() != Token.TokenType.EOF_TOKEN) {
            nextToken = scanToken();
        }
        return returnToken;
    }

    public Token scanToken() {
        Token newToken = new Token();
        boolean charFound = false;
        String data = "";
        //Get rid of white space.
        while (charFound == false){
            if (currentLine.charAt(lineWalker) == ' '){
                lineWalker++;
            }
            else{
                charFound = true;
            }
        }
        Character firstChar = currentLine.charAt(lineWalker);
        data = data + firstChar;
        Character next = null;
        int tokenLength = 0;
        
        if (lineWalker < currentLine.length()-2){
            next = currentLine.charAt(lineWalker+1);
        }
        
        if (Character.isLetter(firstChar)) { //Letter or ID           
            while (Character.isLetter(next)) {
                data = data + next;
                lineWalker++;
                tokenLength++;
                if (lineWalker < currentLine.length()-2){
                    next = currentLine.charAt(lineWalker+1);
                }
                else{
                    break;
                }
            }
            //Numbers can't follow letters.
            if (Character.isDigit(next)) {
                throw new InvalidTokenException("Numbers can't follow letters");
            }
            if (tokenLength == 0) { //Letter
                newToken.setType(Token.TokenType.LETTER_TOKEN);
                newToken.setData(data);
            } else { //ID or keyword
                for (int i = 0; i < 6; i++) { //Check for keyword
                    if (data.equals(keywords[i])) {
                        switch (i) {
                            case 0:
                                newToken.setType(Token.TokenType.ELSE_TOKEN);
                                break;
                            case 1:
                                newToken.setType(Token.TokenType.IF_TOKEN);
                                break;
                            case 2:
                                newToken.setType(Token.TokenType.INT_TOKEN);
                                break;
                            case 3:
                                newToken.setType(Token.TokenType.RETURN_TOKEN);
                                break;
                            case 4:
                                newToken.setType(Token.TokenType.VOID_TOKEN);
                                break;
                            case 5:
                                newToken.setType(Token.TokenType.WHILE_TOKEN);
                                break;
                            default:
                        }
                    } else { //ID
                        newToken.setType(Token.TokenType.ID_TOKEN);
                        newToken.setData(data);
                    }
                }
            }
            TC.addToken(newToken);            
            
          //Digit or Num
        } else if (Character.isDigit(firstChar)) {
            if (next != null){
                while (Character.isDigit(next)) {
                    data = data + next;
                    lineWalker++;
                    tokenLength++;
                    if (lineWalker < currentLine.length()-2){
                        next = currentLine.charAt(lineWalker+1);
                    }
                    else{
                        break;
                    }
                }
            }
            
            //Letters can't follow numbers.
            if (next != null){
                if (Character.isLetter(next)) {
                    throw new InvalidTokenException("Letters can't follow numbers");
                }
            }
            
            if (tokenLength == 0) { //Digit
                newToken.setType(Token.TokenType.DIGIT_TOKEN);
            } else { //NUM
                newToken.setType(Token.TokenType.NUM_TOKEN);
            }
            newToken.setData(data);
            TC.addToken(newToken);
            
            
        //Symbols  
        } else {
            switch (firstChar) {
                case '+':
                    newToken.setType(Token.TokenType.PLUS_TOKEN);
                    break;

                case '-':
                    newToken.setType(Token.TokenType.MINUS_TOKEN);
                    break;

                case '*':
                    if (next == '/') { //Close comment
                        newToken.setType(Token.TokenType.CLOSECOMMENT_TOKEN);
                        lineWalker++;
                    } else { //Mulitply
                        newToken.setType(Token.TokenType.MULTIPLY_TOKEN);
                    }
                    break;

                case '/':
                    if (next == '*') { //Open comment
                        newToken.setType(Token.TokenType.OPENCOMMENT_TOKEN);
                        lineWalker++;
                        //*********Insert comment logic*******
                    } else { //Divide
                        newToken.setType(Token.TokenType.DIVIDE_TOKEN);
                    }
                    break;

                case '<': // < or <=
                    if (next == '=') {
                        newToken.setType(Token.TokenType.LESSTHAN_EQUALTO_TOKEN);
                        lineWalker++;
                    } else {
                        newToken.setType(Token.TokenType.LESSTHAN_TOKEN);
                    }
                    break;

                case '>':
                    ; // > or >=
                    if (next == '=') {
                        newToken.setType(Token.TokenType.GREATERTHAN_EQUALTO_TOKEN);
                        lineWalker++;
                    } else {
                        newToken.setType(Token.TokenType.GREATERTHAN_TOKEN);
                    }
                    break;

                case '=': // = or ==
                    if (next == '=') {
                        newToken.setType(Token.TokenType.COMPARISON_TOKEN);
                        lineWalker++;
                    } else {
                        newToken.setType(Token.TokenType.EQUAL_TOKEN);
                    }
                    break;

                case '!': //!=
                    if (next == '=') {
                        newToken.setType(Token.TokenType.NOTEQUAL_TOKEN);
                        lineWalker++;
                    } else { //Can't have a ! not followed by a =
                        throw new InvalidTokenException("! without a =");
                    }
                    break;

                case ';':
                    newToken.setType(Token.TokenType.SEMICOLON_TOKEN);
                    break;

                case ',':
                    newToken.setType(Token.TokenType.COMMA_TOKEN);
                    break;

                case '(':
                    newToken.setType(Token.TokenType.LEFTPAREN_TOKEN);
                    break;

                case ')':
                    newToken.setType(Token.TokenType.RIGHTPAREN_TOKEN);
                    break;

                case '[':
                    newToken.setType(Token.TokenType.LEFTSQUAREBRACE_TOKEN);
                    break;

                case ']':
                    newToken.setType(Token.TokenType.RIGHTSQUAREBRACE_TOKEN);
                    break;

                case '{':
                    newToken.setType(Token.TokenType.LEFTSQUIGGLEBRACE_TOKEN);
                    break;

                case '}':
                    newToken.setType(Token.TokenType.RIGHTSQUIGGLEBRACE_TOKEN);
                    break;

                default:
                    System.out.println("Unidentified Token");
            }
            lineWalker++;
            if (lineWalker > currentLine.length()) {
                if (inFile.hasNext()){
                    currentLine = inFile.nextLine();
                    lineNum++;
                }
                
            }
        }
        return newToken;
    }
}
